package main

/*
#cgo CFLAGS: -I../lua-5.3.5/src/
#cgo LDFLAGS: -L../lua-5.3.5/src/ -llua -lm -Wl,-rpath=../lua-5.3.5/src/
#include "luacs.h"
#include <stdlib.h>
*/
import "C"
import (
	"bytes"
	"errors"
	"unsafe"
)

// 传入lua脚本字符串,得到下面数据
// 字节码长度+字节码CRC+字节码
func luac(input ...[]byte) ([]byte, error) {
	inLen := len(input)
	if 0 == inLen {
		return nil, errors.New("no script")
	}

	var (
		cStr   = make([]*C.char, inLen)
		outStr *C.uchar
		outLen C.uint
		i      int
	)
	for i = 0; i < inLen; i++ {
		cStr[i] = C.CString(*(*string)(unsafe.Pointer(&input[i])))
	}

	argc, argv := C.int(inLen), &cStr[0]
	if 0 != C.luac(argc, argv, &outStr, &outLen) { // lua 语法错误，报错
		return nil, errors.New(C.GoStringN((*C.char)(unsafe.Pointer(outStr)), C.int(outLen)))
	}

	var (
		luaCode = C.GoBytes(unsafe.Pointer(outStr), C.int(outLen)) // lua字节码
		buffer  bytes.Buffer                                       // 拼接数据
		codeLen = len(luaCode)                                     // 字节码长度
		crcCode = CalculateCRC32(luaCode, uint32(codeLen))         // 计算字节码CRC
	)
	buffer.WriteString("luac") // 头部标识
	for i = 0; i < 4; i++ { // 将lua字节码的长度写到头里面
		buffer.WriteByte(byte(codeLen >> uint8(i*8)))
	}
	for i = 0; i < 4; i++ { // 将lua字节码的crc写到头里面
		buffer.WriteByte(byte(crcCode >> uint8(i*8)))
	}
	buffer.Write(luaCode)

	for i = 0; i < inLen; i++ { // 手动释放 C 资源
		C.free(unsafe.Pointer(cStr[i]))
	}
	C.luac_free()
	return buffer.Bytes(), nil
}
